package org.dfl.plugin.dialogs;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import org.apache.commons.io.FilenameUtils;
import org.apache.log4j.Logger;
import org.dfl.core.model.transitions.JarTransition;
import org.dfl.core.utils.JarUtils;
import org.dfl.messages.Messages;
import org.dfl.plugin.ProjectConstraints;
import org.dfl.plugin.editor.model.TransitionModelElement;
import org.dfl.plugin.utils.WorkbenchUtil;
import org.eclipse.core.resources.IProject;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowData;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;

/**
 * dialog to change JarTransition properties
 * @author Piotr Wlodarczyk
 *
 */
public class JarTransitionPropertiesDialog extends TransitionPropertiesDialog {
	private static Logger logger = Logger.getLogger(JarTransitionPropertiesDialog.class);
	
	private Button addJarButton;
	private Combo packageCombo;
	private Button removeJar;
	private List jarList;
	private Combo classesCombo;
	private Combo methodsCombo;

	public JarTransitionPropertiesDialog(TransitionModelElement transitionModelElement) {
		super(transitionModelElement);
	}
	
	@Override
	protected void addSpecificTransitionElements(final Shell parent) {
		try {		
			{
				Composite composite1 = new Composite(parent, SWT.NONE);
				RowLayout composite1Layout = new RowLayout(
						org.eclipse.swt.SWT.HORIZONTAL);
				GridData composite1LData = new GridData();
				composite1LData.widthHint = 520;
				composite1LData.heightHint = 92;
				composite1LData.grabExcessHorizontalSpace = true;
				composite1.setLayoutData(composite1LData);
				composite1.setLayout(composite1Layout);
				{
					Label jarLabel = new Label(composite1, SWT.NONE);
					RowData jarLabelLData = new RowData();
					jarLabelLData.width = 150;
					jarLabelLData.height = 13;
					jarLabel.setLayoutData(jarLabelLData);
					jarLabel.setText(Messages.JarTransitionPropertiesDialog_0);
				}
				{
					RowData jarListLData = new RowData();
					jarListLData.width = 240;
					jarListLData.height = 79;
					jarList = new List(composite1, SWT.BORDER);
					jarList.setLayoutData(jarListLData);
					
					jarList.removeAll();
					for (String jar : getTransition().getJarList()) {
						jarList.add(jar);
					}
					addEnterKeyListener(jarList);
				}
				{
					Composite composite2 = new Composite(composite1, SWT.NONE);
					GridLayout composite2Layout = new GridLayout();
					composite2Layout.makeColumnsEqualWidth = true;
					RowData composite2LData = new RowData();
					composite2LData.width = 106;
					composite2LData.height = 82;
					composite2.setLayoutData(composite2LData);
					composite2.setLayout(composite2Layout);
					
					GridData jarButtonsLData = new GridData();
					jarButtonsLData.widthHint = 98;
					jarButtonsLData.heightHint = 23;
					{
						addJarButton = new Button(composite2, SWT.PUSH
								| SWT.CENTER);
						addJarButton.setLayoutData(jarButtonsLData);
						addJarButton.setText(Messages.JarTransitionPropertiesDialog_1);
						addJarButton.addListener(SWT.Selection,new Listener(){
							public void handleEvent(Event arg0) {
								IProject project = WorkbenchUtil.getCurrentProject();
								String projectPath = project.getLocation().toFile().getAbsolutePath();
								String prefix;
								if(new File(projectPath + ProjectConstraints.PROJECT_DIR_LIB).exists()){ 
									prefix = ProjectConstraints.PROJECT_DIR_LIB;
								}else{
									prefix = "";
								}
								
								String[] files = new File(projectPath+prefix).list();
								Collection<String> filesPaths = new ArrayList<String>();
								if(files!=null){
									for(String f : files){
										if(!f.equals(".") && !f.equals("..") && f.endsWith(".jar")){
											filesPaths.add(f);
										}
									}
								}
								
								if(filesPaths.isEmpty()){
									DialogsManager.openErrorDialog("No jar files in the project "+prefix+" directory");
									return;
								}

								String res = (String) DialogsManager.openSelectDialog("Select a jar", "Select a jar", filesPaths);
						        // null if user cancels
						        if (res!=null) {
						        	jarList.add(res);
						        	getTransition().setJarList(jarList.getItems());
						        	getTransition().setDir(projectPath+prefix);
						        	refresh();
						        }
							}});
					}
					{
						removeJar = new Button(composite2, SWT.PUSH
								| SWT.CENTER);
						removeJar.setLayoutData(jarButtonsLData);
						removeJar.setText(Messages.JarTransitionPropertiesDialog_2);
						removeJar.addListener(SWT.Selection,new Listener(){
							public void handleEvent(Event arg0) {
								if(jarList.getSelectionIndex()>=0){
									jarList.remove(jarList.getSelectionIndex());
									refresh();
									refreshIODescription();
								}
							}});
					}
				}
			}
			
			Set<String> packages = JarUtils.getPackagesList(getJarFullPathList());
			packageCombo = addComboRow(parent,true, false, Messages.JarTransitionPropertiesDialog_3,packages, getTransition().getPackageStr());
			packageCombo.addModifyListener(new ModifyListener(){
				public void modifyText(ModifyEvent e) {
					if(!packageCombo.getText().equals(getTransition().getPackageStr())){
						getTransition().setPackageStr(packageCombo.getText());
						refreshClasses();
						refreshMethods();
						refreshIODescription();
					}
				}});
			addEnterKeyListener(packageCombo);
			
			HashSet<String> classes = new HashSet<String>(JarUtils.getClasseNamesInPackage(getJarFullPathList(), getTransition().getPackageStr()));
			classesCombo = addComboRow(parent,false, false, Messages.JarTransitionPropertiesDialog_4,classes, getTransition().getClassName());
			setFieldErrorChecking(classesCombo, classesCombo.getText()==null || classesCombo.getText().equals(""), Messages.JarTransitionPropertiesDialog_6); //$NON-NLS-1$
			classesCombo.addModifyListener(new ModifyListener(){
				public void modifyText(ModifyEvent e) {
					setFieldErrorChecking(classesCombo, classesCombo.getText()==null || classesCombo.getText().equals(""), Messages.JarTransitionPropertiesDialog_8); //$NON-NLS-1$
					if(!classesCombo.getText().equals(getTransition().getClassName())){
						try {
							getTransition().setClassName(classesCombo.getText());
						} catch (Exception e1) {
							DialogsManager.openErrorDialog(e1);
							classesCombo.setText(""); //$NON-NLS-1$
							try {
								getTransition().setClassName(null);
							} catch (Exception e2) {}
						}
						refreshMethods();
						refreshIODescription();
					}
				}});
			addEnterKeyListener(classesCombo);
			
			HashSet<String> methods = new HashSet<String>(getTransition().getAvailableMethods());
			methodsCombo = addComboRow(parent,false, false, Messages.JarTransitionPropertiesDialog_10,methods, getTransition().getMethodStr());
			setFieldErrorChecking(methodsCombo, methodsCombo.getText()==null || methodsCombo.getText().equals(""), Messages.JarTransitionPropertiesDialog_12); //$NON-NLS-1$
			methodsCombo.addModifyListener(new ModifyListener(){
				public void modifyText(ModifyEvent e) {
					setFieldErrorChecking(methodsCombo, methodsCombo.getText()==null || methodsCombo.getText().equals(""), Messages.JarTransitionPropertiesDialog_14); //$NON-NLS-1$
					if(!methodsCombo.getText().equals(getTransition().getMethodStr())){
						try {
							getTransition().setMethodStr(methodsCombo.getText());
						} catch (Exception e1) {
							DialogsManager.openErrorDialog(e1);
							methodsCombo.setText(""); //$NON-NLS-1$
							try {
								getTransition().setMethodStr(null);
							} catch (Exception e2) {}
						}
						refreshIODescription();
					}
				}});
			addEnterKeyListener(methodsCombo);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		}
	}
	
	public void refresh() {
		refreshPackages();
		refreshClasses();
		refreshMethods();
	}
	
	private void refreshPackages(){
		// update packages
		Set<String> packages = JarUtils.getPackagesList(getJarFullPathList());
		packageCombo.removeAll();
		for (String packageName : packages) {
			packageCombo.add(packageName);
		}
		packageCombo.setText(getTransition().getPackageStr());
	}
	
	private void refreshClasses(){
		// update classes
		classesCombo.removeAll();
		if(!packageCombo.getText().equals("")){ //$NON-NLS-1$
			java.util.List<String> classes = JarUtils.getClasseNamesInPackage(getJarFullPathList(), packageCombo.getText());
			for (String className : classes) {
				classesCombo.add(className);
			}
			classesCombo.setText(getTransition().getClassName());
		}
		setFieldErrorChecking(classesCombo, classesCombo.getText()==null || classesCombo.getText().equals(""), Messages.JarTransitionPropertiesDialog_18); //$NON-NLS-1$
	}
		
	private void refreshMethods(){
		// update methods
		HashSet<String> methods = new HashSet<String>(getTransition().getAvailableMethods());
		methodsCombo.removeAll();
		for (String methodName : methods) {
			methodsCombo.add(methodName);
		}
		methodsCombo.setText(getTransition().getMethodStr());
		setFieldErrorChecking(methodsCombo, methodsCombo.getText()==null || methodsCombo.getText().equals(""), Messages.JarTransitionPropertiesDialog_20); //$NON-NLS-1$
	}
	private String[] getJarFullPathList(){
		String dir = getTransition().getDir();
		
		String[] items = jarList.getItems();
		String[] jars = new String[items.length];
		for(int i=0; i<items.length;i++){
			jars[i]=FilenameUtils.separatorsToSystem(dir==null?items[i]:(dir+"/"+items[i]));
		}
		return jars;
	}
	@Override
	public JarTransition getTransition() {
		return (JarTransition) super.getTransition();
	}
}
